import { ServletUtils, StringUtils } from "@/util/common";
import { Context } from "@midwayjs/koa";

/**
 * ip地址解析类
 * 
 * @author jn
 */
export class IpUtils {

    public static readonly REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
    public static readonly REGX_IP: string = "((" + IpUtils.REGX_0_255 + "\\.){3}" + IpUtils.REGX_0_255 + ")";
    public static readonly REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + IpUtils.REGX_0_255 + "(\\.\\*){3})|(" + IpUtils.REGX_0_255 + "\\." + IpUtils.REGX_0_255 + ")(\\.\\*){2}" + "|((" + IpUtils.REGX_0_255 + "\\.){3}\\*))";
    // 匹配网段
    public static readonly REGX_IP_SEG = "(" + IpUtils.REGX_IP + "\\-" + IpUtils.REGX_IP + ")";

    /**
     * 获取ip地址
     * @param ctx ctx
     * @returns ip地址
     */
    static getIpAddr(ctx: Context) {
        return ServletUtils.getRequest(ctx);
    }

    /**
     * 获取具体地址
     * @param ctx ctx
     * @returns 具体地址
     */
    static getIpAddress(ctx: Context) {
        return ServletUtils.getAddress(ctx);
    }

    /**
     * 是否为IP
     */
    static isIP(ip: string) {
        return StringUtils.isNotBlank(ip) && ip.match(this.REGX_IP);
    }

    /**
     * 是否为IP，或 *为间隔的通配符地址
     */
    public static isIpWildCard(ip: string) {
        return StringUtils.isNotBlank(ip) && ip.match(this.REGX_IP_WILDCARD);
    }

    /**
     * 检测参数是否在ip通配符里
     */
    public static ipIsInWildCardNoCheck(ipWildCard: string, ip: string) {
        let s1: string[] = ipWildCard.split("\\.");
        let s2: string[] = ip.split("\\.");
        let isMatchedSeg: boolean = true;
        for (let i = 0; i < s1.length && !(s1[i] == "*"); i++) {
            if (!(s1[i] == s2[i])) {
                isMatchedSeg = false;
                break;
            }
        }
        return isMatchedSeg;
    }

    /**
     * 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串
     */
    public static isIPSegment(ipSeg: string) {
        return StringUtils.isNotBlank(ipSeg) && ipSeg.match(this.REGX_IP_SEG);
    }

    /**
     * 判断ip是否在指定网段中
     */
    public static ipIsInNetNoCheck(iparea: string, ip: string) {
        let idx: number = iparea.indexOf("-");
        let sips: string[] = iparea.substring(0, idx).split("\\.");
        let sipe: string[] = iparea.substring(idx + 1).split("\\.");
        let sipt: string[] = ip.split("\\.");
        let ips = 0, ipe = 0, ipt = 0;
        for (let i = 0; i < 4; ++i) {
            ips = ips << 8 | Number(sips[i]);
            ipe = ipe << 8 | Number(sipe[i]);
            ipt = ipt << 8 | Number(sipt[i]);
        }
        if (ips > ipe) {
            let t: number = ips;
            ips = ipe;
            ipe = t;
        }
        return ips <= ipt && ipt <= ipe;
    }

    static isMatchedIp(filter: string, ip: string) {
        if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip)) {
            return false;
        }
        let ips: string[] = filter.split(";");
        for (const key in ips) {
            if (Object.prototype.hasOwnProperty.call(ips, key)) {
                let iStr: string = ips[key];
                if (this.isIP(iStr) && iStr == ip) {
                    return true;
                }
                else if (this.isIpWildCard(iStr) && this.ipIsInWildCardNoCheck(iStr, ip)) {
                    return true;
                }
                else if (this.isIPSegment(iStr) && this.ipIsInNetNoCheck(iStr, ip)) {
                    return true;
                }
            }
        }
        return false;
    }

}